package com.yxw.yx_hotel.utils;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.yxw.yx_hotel.vo.UserTokenVo;
import com.yxw.yxnet_cd_center.common.constant.CommonConstant;
import com.yxw.yxnet_cd_center.common.exception.BaseException;
import com.yxw.yxnet_cd_center.common.result.TokenInfo;
import com.yxw.yxnet_cd_center.common.utils.BaseDateTime;

import com.yxw.yxnet_cd_center.common.utils.RSAUtil;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.time.LocalDateTime;
import lombok.extern.slf4j.Slf4j;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;

/**
 * @author Administrator
 */
@Slf4j
public class JwtUtil {

    /**
     * jwt 密钥
     */
    private static final String JWT_TOKEN = "hotel!r@HT1645#T$6gR3";
    private static final String PRIVATE_KEY_STR = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMr5lzxLW_4AbAQUOzqVIOGLXelnDq5FZiifSLOE3llSeUbnuaKj2CbgWyHxLgLcNmd6-GkRrHAVWw8jloKF2AkzW62wGr2TeoLArMAULOJpAcp5LURKOpcpZ02QqZceC2lEcYQix6JBMe1zmLQxPzEZbvnYEqaGQkfl0aU"+
            "32PjfAgMBAAECgYBjJDRtu_VsBLK970_a1nqgEB3H4pG2J6m1j8_H989PW8xnCMqQmWz72DxLQO2TchKUyujJEVvjx1qZ820RxeR2Ag8xhMTszQ_4jlgptDK02kxfF_YSBOgsqcOWjcG5gafyaRf-PbqmKDA2apUgPR6rgp3UgY2ULIAbtd9y3DJHEQJBAP2ahUtXilJvwfVhY2rbAYQnCfDYoVnV-rc2VmwdVJJG9XM17ujoTZfEPGurHasMjF"+
            "VeC-wQOgAIjuYrnQDrRwkCQQDM5JjTxtu_jWY07KBKkKwo-SmZBw4oikgXb7u4bkrJwB4L5bjEoCU1GwLYMCqhnwJjLT0ZgVGIcD8IX055JxKnAkA_IQnxWVdLchp8NMQEw4O7G-SzmZmAvW1t0g7tVtfImfVbup9ARyOZlfXcb3oxLCx6y7B4EQn_HCJGVbD9m5PRAkAPR1CaIi8KxqmDcs21Ibqkx4exkJQes8kSblOKOjc7eicDbhrsFqEPp7"+
            "b7lgPnz2qnKJ1wxHLnAK_CmRDJ-f7rAkAd0cGSBofiJu7vhydin5oY8FE_GPYfzl3hl0UbUFSTdIi75eqwPu2-9Ay-8T0L3cZg5YmccLc1TS-T8vkHERBb";
    private static final String PUBLIC_KEY_STR = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK-Zc8S1v-AGwEFDs6lSDhi13pZw6uRWYon0izhN5ZUnlG57mio9gm4Fsh8S4C3DZnevhpEaxwFVsPI5aChdgJM1utsBq9k3qCwKzAFCziaQHKeS1ESjqXKWdNkKmXHgtpRHGEIseiQTHtc5i0MT8xGW752BKmhkJH5dGlN9j43wIDAQAB";
    
    /**
     * 系统认证
     */
    public static final String TOKEN = "token";    
    /**
     * 生成token，自定义过期时间 毫秒
     * @param yxUserTokenVo 参数封装
     * @return String
     */
    public static String generateToken(UserTokenVo yxUserTokenVo, Long checkCode) {
        RSAPublicKey oRSAPublicKey = null;
        /*try
        {
            oRSAPublicKey = RSAUtil.getPublicKey(PUBLIC_KEY_STR);
        }
        catch(Exception oException)
        {
            log.error("认证失败,初始化RSAPublicKey失败");
            return null;
        }*/        
        RSAPrivateKey oRSAPrivateKey = null;
        try
        {
            oRSAPrivateKey = RSAUtil.getPrivateKey(PRIVATE_KEY_STR);
        }
        catch(Exception oException)
        {
            log.error("生成失败,初始化PrivateKey失败");
            return null;
        }            
        try {
            // 私钥和加密算法
            Algorithm algorithm = Algorithm.RSA512(oRSAPublicKey, oRSAPrivateKey);
            // 设置头部信息
            //Map<String, Object> header = new HashMap<>(2);
            //header.put("Type", "Jwt");
            //header.put("alg", "RSA512");

            return JWT.create()                    
                    .withClaim("checkCode", checkCode)
                    .withClaim("userId", yxUserTokenVo.getUserId())
                    .withClaim("token", JSONObject.toJSONString(yxUserTokenVo))
                    .withClaim("expireTime",new Date(new Date().getTime() + 30*60*1000))
                    .sign(algorithm);
            //.withHeader(header)
        } catch (JWTCreationException | IllegalArgumentException e) {
            log.error("generate token occur error, error is:{}", e);
            return null;
        }
    }
    /**
     * 检验token是否正确
     * @param token token
     * @return YxSysUserTokenVo
    */
    public static UserTokenVo parseToken(String token) {
        if(StrUtil.isBlank(token))
        {
            log.error("认证失败,httpRequest中不含token");
            throw new BaseException("token不能为空值");
        }        
        RSAPublicKey oRSAPublicKey = null;
        try
        {
            oRSAPublicKey = RSAUtil.getPublicKey(PUBLIC_KEY_STR);
        }
        catch(Exception oException)
        {
            log.error("认证失败,初始化PublicKey失败");
            return null;
        }
        RSAPrivateKey oRSAPrivateKey = null;      
        Algorithm algorithm = Algorithm.RSA512(oRSAPublicKey, oRSAPrivateKey);
        JWTVerifier verifier = JWT.require(algorithm).build();
        DecodedJWT jwt = verifier.verify(token);
        String yxSysUserTokenVo = jwt.getClaim("token").asString();
        return JSON.parseObject(yxSysUserTokenVo, UserTokenVo.class);
    }    
    public static UserTokenVo getUserTokenVoByHttpRquest(HttpServletRequest httpRequest){
        String token = httpRequest.getHeader(TOKEN);
        if(StrUtil.isBlank(token))
        {
            log.error("认证失败,httpRequest中不含token");
            return null;
        }
        RSAPublicKey oRSAPublicKey = null;
        try
        {
            oRSAPublicKey = RSAUtil.getPublicKey(PUBLIC_KEY_STR);
        }
        catch(Exception oException)
        {
            log.error("认证失败,初始化PublicKey失败");
            return null;
        }
        RSAPrivateKey oRSAPrivateKey = null;
        /*try
        {
            oRSAPrivateKey = RSAUtil.getPrivateKey(PRIVATE_KEY_STR);
        }
        catch(Exception oException)
        {
            log.error("认证失败,初始化RSAPrivateKey失败");
            return null;
        }*/
        DecodedJWT oDecodedJWT = null;
        try {
            oDecodedJWT = JWT.require(Algorithm.RSA512(oRSAPublicKey, oRSAPrivateKey)).build().verify(token);
        } 
        catch (Exception e) {
            log.error("token认证失败,TokenUtil->getTokenInfoByToken  e.getMessage:{}", e.getMessage());
            return null;
        }
        String tokenString = oDecodedJWT.getClaim(token).asString();
        return JSON.parseObject(tokenString, UserTokenVo.class);
    }
    /**
     * 从token获取userId
     *
     * @param token
     * @return
     */
    public static Long getUserIdFromToken(String token) {
        DecodedJWT oDecodedJWT = null;
        try 
        {
            oDecodedJWT = JWT.decode(token);
        } 
        catch (JWTDecodeException e) 
        {
            System.out.println("TokenUtil->getTokenInfoByTokenNoVerify  e.getMessage():" + e.getMessage());
            return null;
        }
        Map<String, Claim> map = oDecodedJWT.getClaims();
        Claim oClaim = map.get("userId");
        if(null != oClaim)
        {
            Long userId = oClaim.asLong();
            return userId;
        }
        else
        {
            return null;
        }
    }
}
